import {
  BadRequestException,
  Body,
  ConflictException,
  Controller,
  Delete,
  ForbiddenException,
  Get,
  HttpCode,
  HttpStatus,
  Post,
  Put,
  Req,
  Res,
  UseGuards,
} from '@nestjs/common';
import { CreateGameDto } from './dto/create-game.dto';
import { GamesService } from './games.service';
import { Response } from 'express';
import { JwtAuthGuard } from 'src/guards/jwt-auth.guard';
import { jwtRequest } from 'src/common/interfaces/jwt-request.interface';

@UseGuards(JwtAuthGuard)
@Controller('games')
export class GamesController {
  constructor(private gameService: GamesService) {}

  @Post()
  async create(@Body() createGameDto: CreateGameDto) {
    const startedGame = await this.gameService.findStarted();
    if (startedGame !== null) {
      throw new BadRequestException(
        '请等待游戏结束之后，再创建',
        '游戏已经开始',
      );
    }

    this.gameService.create(createGameDto);
  }

  /**
   * 加入一场游戏
   */
  @Put('join')
  @HttpCode(204)
  async join(@Req() req: jwtRequest) {
    const {
      user: { userId },
    } = req;

    // 如果令牌里没有用户标识，则不能加入游戏
    if (!userId) {
      throw new BadRequestException('令牌格式不正确', '授权错误');
    }

    // 如果没有正在进行的一场游戏，则不能加入游戏
    const startedGame = await this.gameService.findStarted();
    if (startedGame === null) {
      throw new ConflictException('请等待游戏开始之后，再参加', '游戏未开始');
    }

    // 判断是不是在游戏加入阶段
    const isJoinStage = this.gameService.isJoinStage(startedGame);
    if (!isJoinStage) {
      throw new ConflictException(
        '请在游戏参加阶段，加入游戏',
        '现在不是参加阶段',
      );
    }

    const joinResult = await this.gameService.join(userId);
    if (!joinResult.nModified) {
      throw new ConflictException(
        '你已经参加了游戏，请不要重复参加',
        '已经参加游戏',
      );
    }
  }

  /**
   * 查询所有游戏
   * @returns 所有游戏
   */
  @Get()
  findAll() {
    return this.gameService.findAll();
  }

  /**
   * 查询已经开始的一场游戏
   * @returns 已经开始的一场游戏
   */
  @Get('started')
  async findStarted(@Res() res: Response) {
    const started = await this.gameService.findStarted();

    if (started === null) {
      res.status(HttpStatus.NOT_FOUND).send();
    }

    res.send(started);
  }

  /**
   * 猜涨跌
   * @param req 请求对象
   * @param isRise 是否涨
   */
  @Put('rise-fall')
  async guessRiseFall(@Req() req: jwtRequest, @Body('isRise') isRise: boolean) {
    const {
      user: { userId },
    } = req;

    // 如果没有正在进行的一场游戏，则不能猜涨跌
    const startedGame = await this.gameService.findStarted();
    if (startedGame === null) {
      throw new ConflictException('请等待游戏开始之后，再猜涨跌', '游戏未开始');
    }

    // 判断是否已经加入了游戏
    const hasJoined = this.gameService.hasJoined(startedGame, userId);
    if (!hasJoined) {
      throw new ConflictException('你没有加入到游戏，不能猜涨跌', '未加入游戏');
    }

    // 判断是不是在游戏加入阶段
    const isJoinStage = this.gameService.isJoinStage(startedGame);
    if (isJoinStage) {
      throw new ConflictException(
        '请在猜涨跌的阶段进行游戏',
        '现在不是猜涨跌阶段',
      );
    }

    // 判断是否是猜涨跌的时间
    const inGuessRiseFallTime = this.gameService.inGuessRiseFallTime();
    if (!inGuessRiseFallTime) {
      throw new ConflictException(
        '现在还不能猜涨跌，请在09:30-13:00猜涨跌',
        '不在猜涨跌的阶段',
      );
    }

    this.gameService.guessRiseFall(startedGame, userId, isRise);
  }

  /**
   * 结算今天的游戏结果
   */
  @Delete()
  async deleteAll() {
    return await this.gameService.deleteAll();
  }

  @Get('today/results')
  async findTodayResults(@Req() req: jwtRequest) {
    const {
      user: { isAdmin },
    } = req;

    if (!isAdmin) {
      throw new ForbiddenException(
        '成为管理员之后，才能进行此操作',
        '不是管理员',
      );
    }

    return isAdmin;
  }
}
